home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1999 March / EnigmA AMIGA RUN 35 (1999)(G.R. Edizioni)(IT)[!][issue 1999-03].iso / earcd / grafica / amhelios / helios.cpp < prev    next >
Text File  |  1999-01-01  |  76KB  |  2,380 lines

  1. ////////////////////////////////////////////////////////////
  2. //
  3. //  HELIOS.CPP - Radiosity Renderer for MS-Windows Main
  4. //               Module
  5. //
  6. //  Version:    1.03A
  7. //
  8. //  History:    94/08/23 - Version 1.00A release.
  9. //              94/09/07 - Added CheckAbort and user-
  10. //                         requested abort logic.
  11. //                       - Added WM_QUERYENDSESSION and
  12. //                         WM_CLOSE message handlers.
  13. //                       - Added AbortCalc modeless dialog
  14. //                         box.
  15. //              94/09/23 - Added elapsed calculation time to
  16. //                         Convergence Statistics message
  17. //                         box.
  18. //              94/09/27 - Modified IDM_SETCONVERGE case
  19. //                         logic to prevent Rendering menu
  20. //                         option from being enabled when
  21. //                         display type is H_NONE.
  22. //              94/10/02 - Made Set Camera and Specify
  23. //                         View dialog boxes modeless.
  24. //                       - Revised cursor display logic.
  25. //              94/10/14 - Added ContrastError string.
  26. //                       - Modified SetDisplay dialog box
  27. //                         function.
  28. //              94/11/19 - Added OutOfMemory error reporting
  29. //                         for SynCamera::Preview,
  30. //                         SynCamera::Shoot, WinBitmap::Open
  31. //                         and WinBitmap::Display function
  32. //                         call failures.
  33. //              94/11/25 - Added CenterDialog and
  34. //                         FileOpenHook functions.
  35. //                       - Modified SetEntityDir, SetCamera,
  36. //                         SetView, SetConverge, AbortCalc,
  37. //                         SetDisplay, and About to center
  38. //                         dialog boxes.
  39. //              94/12/01 - Added palette flag and
  40. //                         color resolution initialization
  41. //                         to InitInstance.
  42. //                       - Added color resolution logic to
  43. //                         SetDisplay dialog box.
  44. //              94/12/04 - Added bitmap color quantization
  45. //                         capability to IDM_RENDER,
  46. //                         IDM_REDISPLAY and IDD_UPD_DISPLAY
  47. //                         case logic.
  48. //                       - Added modeless RenderMsg dialog
  49. //                         box.
  50. //              94/12/06 - Added WM_QUERYPALETTE and
  51. //                         WM_PALETTECHANGED message
  52. //                         handlers.
  53. //                       - Deleted <windows.h>, <stdio.h>
  54. //                         and <math.h> include directives.
  55. //                       - Added "general.h" include
  56. //                         directive.
  57. //                       - Made SetDisplay dialog box
  58. //                         modeless.
  59. //                       - Added check for invalid display
  60. //                         type to InitInstance.
  61. //                       - Added AppTitle string.
  62. //              94/12/08 - Added IDM_HELP_CONTENTS and
  63. //                         IDM_HELP_HELP case logic.
  64. //                       - Added Windows Help cancel to
  65. //                         WM_DESTROY case logic.
  66. //                       - Added HelpFileName string.
  67. //                       - Added "win_help.h" include
  68. //                         directive.
  69. //              94/12/11 - Revised FrontDistErr string.
  70. //              94/12/16 - Version 1.01A release.
  71. //              94/12/19 - Changed OutputFilterSpec string
  72. //                         to support TARGA files.
  73. //                       - Changed IDM_SAVEAS case logic to
  74. //                         support TARGA files.
  75. //                       - Added static WinTarga object.
  76. //                       - Added "win_tga.h" include
  77. //                         directive.
  78. //              94/12/24 - Modified SetCamera to handle
  79. //                         window scale and projection type.
  80. //                       - Added WindowScaleError string.
  81. //              95/02/05 - Version 1.02A release.
  82. //              95/03/09 - Modified IDM_FILEOPEN case logic
  83. //                         to prevent GetSaveFileName from
  84. //                         overwriting hook function pointer.
  85. //              95/03/26 - Revised IDM_RENDER case logic to
  86. //                         support antialiasing.
  87. //                       - Added hourglass cursor to
  88. //                         IDM_FILEOPEN case logic.
  89. //                       - Deleted RenderInProgress and
  90. //                         QuantInProgress strings.
  91. //                       - Added IDM_SETCOLOR case.
  92. //                       - Added SetColor function.
  93. //                       - Made pScroll and DispType global.
  94. //                       - Added DisplayBitmap function.
  95. //              95/06/26 - Modified SetCamera, SetView,
  96. //                         SetDisplay and SetColor to
  97. //                         update display when OK button
  98. //                         selected.
  99. //              95/07/16 - Revised menu item graying logic.
  100. //                       - Added DisableMenu and EnableMenu
  101. //                         functions.
  102. //                       - Revised IDM_REDISPLAY case logic
  103. //                         to properly handle redisplay when
  104. //                         no bitmap is currently displayed.
  105. //                       - Added RadCalcDone flag.
  106. //              95/07/21 - Version 1.02B release.
  107. //              95/09/30 - Revised About function to
  108. //                         properly respond to WM_COMMAND
  109. //                         messages under Windows NT.
  110. //              95/10/10 - Revised WM_HSCROLL and WM_VSCROLL
  111. //                         case statements to process scroll
  112. //                         bar messages under Windows NT.
  113. //              96/02/14 - Version 1.02C release.
  114. //              96/02/21 - Modified DisplayBitmap to call
  115. //                         SynCamera::Abort.
  116. //              96/02/29 - Modified IDM_FILEOPEN case logic
  117. //                         to initialize camera view system.
  118. //              96/03/30 - Added camera focus position to
  119. //                         SetView dialog box handler.
  120. //                       - Added IDM_STATISTICS case.
  121. //                       - Added DisplayStats function.
  122. //                       - Modified DisableMenu and
  123. //                         EnableMenu functions.
  124. //                       - Deleted Environment Statistics
  125. //                         message box function call from
  126. //                         IDM_FILEOPEN case statement.
  127. //                       - Modified IDM_FILEOPEN case logic
  128. //                         to display default wireframe view
  129. //                         of environment.
  130. //                       - Added IDM_SETDOLLY, IDM_SETORBIT,
  131. //                         IDM_SETPAN, IDM_SETROTATE,
  132. //                         IDM_SETTILT, IDM_SETZOOM,
  133. //                         IDM_DEFVIEW, WM_LBUTTONDOWN,
  134. //                         WM_LBUTTONUP and WM_RBUTTONDOWN
  135. //                         case statements.
  136. //                       - Made menu handle in MainWndProc
  137. //                         static and initialized from
  138. //                         from WM_CREATE case statement.
  139. //                       - Added MoveType global variable.
  140. //                       - Added SetMovementType,
  141. //                         UpdateDolly, UpdateOrbit,
  142. //                         UpdatePan, UpdateRotate,
  143. //                         UpdateTilt, UpdateZoom,
  144. //                         UpdateCameraDialog and
  145. //                         UpdateViewDialog functions.
  146. //                       - Modified DisableMenu and
  147. //                         EnableMenu functions.
  148. //                       - Added camera tilt field to
  149. //                         SetCamera.
  150. //                       - Removed View Direction and
  151. //                         View-Up Vector fields from
  152. //                         SetView.
  153. //                       - Deleted HorzError, VertError,
  154. //                         ViewDirName, ViewUpName and
  155. //                         ViewUpError static strings.
  156. //                       - Added FocusError and TiltError
  157. //                         static strings.
  158. //                       - Deleted "spheric3.h" include
  159. //                         directive.
  160. //              96/04/01 - Version 1.03A release.
  161. //
  162. //  Compilers:  Microsoft Visual C/C++ Professional V1.5
  163. //              Borland C++ Version 4.5
  164. //
  165. //  Author:     Ian Ashdown, P.Eng.
  166. //              byHeart Software Limited
  167. //              620 Ballantree Road
  168. //              West Vancouver, B.C.
  169. //              Canada V7S 1W3
  170. //              Tel. (604) 922-6148
  171. //              Fax. (604) 987-7621
  172. //
  173. //  Copyright 1994-1996 byHeart Software Limited
  174. //
  175. //  The following source code has been derived from:
  176. //
  177. //    Ashdown, I. 1994. Radiosity: A Programmer's
  178. //    Perspective. New York, NY: John Wiley & Sons.
  179. //
  180. //  It may be freely copied, redistributed, and/or modified
  181. //  for personal use ONLY, as long as the copyright notice
  182. //  is included with all source code files.
  183. // 
  184. //////////////////////////////////////////////////////////// 
  185.  
  186. #include "general.h"
  187. #include <windowsx.h>
  188. #include <commdlg.h>
  189. #include "error.h"
  190. #include "parse.h"
  191. #include "syn_cam.h"
  192. #include "win_bmap.h"
  193. #include "win_tga.h"
  194. #include "win_meta.h"
  195. #include "win_sbar.h"
  196. #include "win_help.h"
  197.  
  198. #if (defined(_HEMI_CUBE) || defined(_CUBIC_TETRA))
  199. #include "prog_rad.h"
  200. #elif defined(_RAY_CAST)
  201. #include "ray_rad.h"
  202. #else
  203. #include "rad_eqn.h"
  204. #endif
  205.  
  206. #include "resource.h"
  207. #include "helios.h"
  208.  
  209. static BOOL AbortFlag = FALSE;  // User-requested abort
  210. static BOOL InCalc = FALSE;     // Calculations in progress
  211.  
  212. // Radiosity calculations completed
  213. static BOOL RadCalcDone = FALSE;
  214.  
  215. static char EntityDir[MaxLen];  // Entity directory
  216. static char WorldName[MaxLen];  // World file name buffer
  217. static char BitmapName[MaxLen]; // Bitmap file name buffer
  218. static char FileTitle[MaxLen];  // File title buffer
  219. static char StrBuffer[MaxLen];  // Temporary string buffer
  220.  
  221. static int DispType = H_NONE;   // Display type
  222. static int MoveType = H_LOCK;   // Camera movement type
  223.  
  224. static HINSTANCE hInst;         // Current instance handle
  225.  
  226. // Dialog box handles
  227. static HWND hAbortDlg;          // Abort calculations
  228. static HWND hQuantDlg;          // Quantization message
  229. static HWND hRenderDlg;         // Rendering message
  230. static HWND hSetCameraDlg;      // Camera parameters
  231. static HWND hSetColorDlg;       // Color parameters
  232. static HWND hSetDisplayDlg;     // Display parameters
  233. static HWND hSetViewDlg;        // View parameters
  234.  
  235. // Dialog box exported function prolog pointers
  236. static DLGPROC pcfunc;          // Camera parameters
  237. static DLGPROC pdfunc;          // Display parameters
  238. static DLGPROC pofunc;          // Coloor parameters
  239. static DLGPROC pvfunc;          // View parameters
  240.  
  241. static OPENFILENAME Ofn;        // Open filename structure
  242.  
  243. // Synthetic camera
  244. static SynCamera Camera(640, 480, -180.0, 90.0, 0.0, 0.0);
  245.  
  246. static Environ Environment;     // Environment
  247. static Parse Parser;            // World file parser
  248. static WinBitmap Bitmap;        // Bitmap manager
  249. static WinMetaFile Wire;        // Metafile manager
  250. static WinScroll *pScroll;      // Scroll bar manager ptr
  251. static WinTarga Targa;          // Targa file manager
  252.  
  253. // Radiosity equation solver
  254. #if (defined(_HEMI_CUBE) || defined(_CUBIC_TETRA))
  255. static ProgRad Radiosity;       // Progressive radiosity
  256. #elif defined(_RAY_CAST)
  257. static RayRad Radiosity;        // Ray cast radiosity
  258. #else
  259. static RadEqnSolve Radiosity;   // Dummy equation solver
  260. #endif
  261.  
  262. static const char AppName[] = "HELIOS";
  263. static const char AppTitle[] = "HELIOS Radiosity Renderer";
  264. static const char BitmapSection[] = "Bitmap";
  265. static const char CalcInProgress[] = "Radiosity "
  266.     "calculations in progress ...";
  267. static const char ContrastError[] = "Contrast factor must "
  268.     "be greater than zero";
  269. static const char EyeDistError[] = "Front distance is "
  270.     "behind eye position";
  271. static const char FocusError[] = "Focus position cannot be"
  272.     "equal to eye position";
  273. static const char FrontDistError[] = "Front distance must "
  274.     "be greater than back distance";
  275. static const char GammaError[] = "Gamma value must be "
  276.     "greater than zero";
  277. static const char HeightEntry[] = "Height";
  278. static const char HelpFileName[] = "HELIOS.HLP";
  279. static const char InitFileName[] = "HELIOS.INI";
  280. static const char InvalidDisplay[] = "HELIOS requires a "
  281.     "display with at least 256 colors";
  282. static const char MaxStepError[] = "Maximum number of "
  283.     "steps must be between 1 and 2000";
  284. static const char NoiseError[] = "Noise level must be "
  285.     "between 0 and 8";
  286. static const char PixelError[] = "Pixel values must be "
  287.     "between 32 and 1024";
  288. static const char StopError[] = "Stopping criterion must be"
  289.     "between 0.0 and 1.0";
  290. static const char TiltError[] = "Tilt angle must be between"
  291.     " 0.0 and 360.0 degrees";
  292. static const char WidthEntry[] = "Width";
  293. static const char ViewDistError[] = "View distance must be "
  294.     "greater than zero";
  295. static const char WindowScaleError[] = "Window scaling "
  296.     "factor must be greater than zero";
  297. static const char WireClass[] = "WIRE";
  298.  
  299. // File type filters
  300. static const char InputFilterSpec[128] =
  301.     "World Files (*.WLD)\0*.WLD\0All Files (*.*)\0*.*\0";
  302. static const char OutputFilterSpec[128] =
  303.     "BMP Files (*.BMP)\0*.BMP\0TARGA Files (*.TGA)\0*.TGA\0";
  304.  
  305. static const int MaxStep = 2000;
  306. static const int MinPixel = 32;
  307. static const int MaxPixel = 1024;
  308.  
  309. int WINAPI WinMain( HINSTANCE hinstance, HINSTANCE hpinst,
  310.     LPSTR pcmdline, int cmdshow )
  311. {
  312.   MSG msg;      // Window message
  313.  
  314.   // Initialize user-request abort flag
  315.   AbortFlag = FALSE;
  316.  
  317.   // Other instances of application running ?
  318.   if (!hpinst)
  319.     if (!InitApplication(hinstance))
  320.       return FALSE;
  321.  
  322.   // Initialize current instance
  323.   if (!InitInstance(hinstance, cmdshow))
  324.       return FALSE;
  325.  
  326.   // Process window messages
  327.   while (GetMessage(&msg, NULL, NULL, NULL))
  328.   {
  329.     // Check for "Set Camera" dialog message
  330.     if (hSetCameraDlg != NULL)
  331.       if (IsDialogMessage(hSetCameraDlg, &msg) == TRUE)
  332.         continue;
  333.  
  334.     // Check for "Set Color Parameters" dialog message
  335.     if (hSetColorDlg != NULL)
  336.       if (IsDialogMessage(hSetColorDlg, &msg) == TRUE)
  337.         continue;
  338.  
  339.     // Check for "Set Display Parameters" dialog message
  340.     if (hSetDisplayDlg != NULL)
  341.       if (IsDialogMessage(hSetDisplayDlg, &msg) == TRUE)
  342.         continue;
  343.  
  344.     // Check for "Specify View" dialog message
  345.     if (hSetViewDlg != NULL)
  346.       if (IsDialogMessage(hSetViewDlg, &msg) == TRUE)
  347.         continue;
  348.  
  349.     TranslateMessage(&msg);
  350.     DispatchMessage(&msg);
  351.   }
  352.   return (int) msg.wParam;
  353. }
  354.  
  355. // Initialize window data and register window classes
  356. static BOOL InitApplication( HINSTANCE hinstance )
  357. {
  358.   WNDCLASS wc;  // Window class
  359.  
  360.   // Register main window class
  361.   wc.style = CS_VREDRAW | CS_HREDRAW;
  362.   wc.lpfnWndProc = (WNDPROC) MainWndProc;
  363.   wc.cbClsExtra = 0;
  364.   wc.cbWndExtra = 0;
  365.   wc.hInstance = hinstance;
  366. #if defined(_CUBIC_TETRA)
  367.   wc.hIcon = LoadIcon(hinstance, "HELIOS_C");
  368. #elif defined(_HEMI_CUBE)
  369.   wc.hIcon = LoadIcon(hinstance, "HELIOS_H");
  370. #elif defined(_RAY_CAST)
  371.   wc.hIcon = LoadIcon(hinstance, "HELIOS_R");
  372. #else
  373.   wc.hIcon = LoadIcon(hinstance, "HELIOS_S");
  374. #endif
  375.   wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  376.   wc.hbrBackground = (HBRUSH) GetStockObject(LTGRAY_BRUSH);
  377.   wc.lpszMenuName =  "HeliosMenu";
  378.   wc.lpszClassName = AppName;
  379.  
  380.   if (!RegisterClass(&wc))
  381.     return FALSE;
  382.  
  383.   // Register wireframe window class
  384.   wc.lpfnWndProc = (WNDPROC) WireWndProc;
  385.   wc.hIcon = NULL;
  386.   wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
  387.   wc.lpszClassName = WireClass;
  388.  
  389.   return (RegisterClass(&wc) ? TRUE : FALSE);
  390. }
  391.  
  392. // Save instance handle and create main window
  393. static BOOL InitInstance( HINSTANCE hinstance, int
  394.     cmdshow )
  395. {
  396.   HDC hdc;      // Device context
  397.   HWND hwnd;    // Main window handle
  398.  
  399.   hInst = hinstance;    // Save current instance handle
  400.  
  401.   // Create main window for current instance
  402.   hwnd = CreateWindow(AppName, AppTitle,
  403.       WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL,
  404.       CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  405.       CW_USEDEFAULT, NULL, NULL, hinstance, NULL);
  406.       
  407.   if (hwnd == 0)
  408.     return FALSE;
  409.  
  410.   // Initialize open filename structure
  411.   Ofn.lStructSize = sizeof(OPENFILENAME);
  412.   Ofn.hwndOwner = hwnd;
  413.   Ofn.lpstrFilter = NULL;
  414.   Ofn.lpstrCustomFilter = NULL;
  415.   Ofn.nMaxCustFilter = 0;
  416.   Ofn.nFilterIndex = 1;
  417.   Ofn.lpstrFile = NULL;
  418.   Ofn.nMaxFile = MaxLen;
  419.   Ofn.lpstrInitialDir = NULL;
  420.   Ofn.lpstrFileTitle = FileTitle;
  421.   Ofn.nMaxFileTitle = MaxLen;
  422.   Ofn.lpstrTitle = NULL;
  423.   Ofn.lpstrDefExt = NULL;
  424.  
  425.   // Initialize modeless dialog box handles
  426.   hSetCameraDlg = NULL;
  427.   hSetColorDlg = NULL;
  428.   hSetDisplayDlg = NULL;
  429.   hSetViewDlg = NULL;
  430.  
  431.   hdc = GetDC(NULL);    // Get screen device context
  432.  
  433.   // Determine display device capabilities
  434.   if ((GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) == 0)
  435.   {
  436.     // Check for 15-bit or better display
  437.     if (GetDeviceCaps(hdc, BITSPIXEL) < 15)
  438.     {
  439.       MessageBox(NULL, InvalidDisplay, AppTitle, MB_OK);
  440.       ReleaseDC(NULL, hdc);
  441.       return FALSE;
  442.     }
  443.  
  444.     // No palette
  445.     Bitmap.SetPaletteFlag(FALSE);
  446.     Bitmap.SetRGBFlag(TRUE);
  447.   }
  448.   else
  449.   {
  450.     // Check for 256-color display
  451.     if (GetDeviceCaps(hdc, COLORRES) < 8)
  452.     {
  453.       MessageBox(NULL, InvalidDisplay, AppTitle, MB_OK);
  454.       ReleaseDC(NULL, hdc);
  455.       return FALSE;
  456.     }
  457.  
  458.     // Palette-mapped display
  459.     Bitmap.SetPaletteFlag(TRUE);
  460.     Bitmap.SetRGBFlag(FALSE);
  461.   }
  462.  
  463.   ReleaseDC(NULL, hdc);         // Release device context
  464.  
  465.   ShowWindow(hwnd, cmdshow);    // Show the window
  466.   UpdateWindow(hwnd);           // Paint the client area
  467.  
  468.   return TRUE;
  469. }
  470.  
  471. // Main window message handler
  472. LRESULT WINAPI MainWndProc( HWND hwnd, UINT msg, WPARAM
  473.     wparam, LPARAM lparam )
  474. {
  475.   static short client_x;        // Client area width
  476.   static short client_y;        // Client area height
  477.   static short mouse_x;         // Mouse x-axis position
  478.   static short mouse_y;         // Mouse y-axis position
  479.   static short wire_x;          // Wireframe window width
  480.   static short wire_y;          // Wireframe window height
  481.   static HWND hwnd_wire;        // Wireframe window handle
  482.   static HMENU hmenu;           // Menu handle
  483.   int mouse_dx;                 // Mouse x-axis delta
  484.   int mouse_dy;                 // Mouse y-axis delta
  485.   BOOL redraw;                  // Redraw flag
  486.   BOOL status;                  // Status flag
  487.   DLGPROC pfunc;                // Exported fcn prolog ptr
  488.   HCURSOR hcursor;              // Cursor handle
  489.   HDC hdc;                      // Device context handle
  490.   PAINTSTRUCT ps;               // Window paint structure
  491.   POINT pos;                    // Point co-ordinates
  492.   RECT rc;                      // Rectangle co-ordinates
  493.  
  494.   switch (msg)
  495.   {
  496.     case WM_CREATE:     // Create window
  497.       // Instantiate scroll bar manager
  498.       pScroll = new WinScroll(hwnd);
  499.  
  500.       hmenu = GetMenu(hwnd);        // Get menu handle
  501.  
  502.       // Create dialog box procedure instance thunks
  503.       pcfunc = (DLGPROC) MakeProcInstance((FARPROC)
  504.           SetCamera, hInst);
  505.       pdfunc = (DLGPROC) MakeProcInstance((FARPROC)
  506.           SetDisplay, hInst);
  507.       pofunc = (DLGPROC) MakeProcInstance((FARPROC)
  508.           SetColor, hInst);
  509.       pvfunc = (DLGPROC) MakeProcInstance((FARPROC)
  510.           SetView, hInst);
  511.       break;
  512.     case WM_SIZE:       // Get client area dimensions
  513.       client_x = LOWORD(lparam);
  514.       client_y = HIWORD(lparam);
  515.       switch (DispType)
  516.       {
  517.         case H_WIRE:
  518.           // Update wireframe display
  519.           CalcWireDim(client_x, client_y, &wire_x, &wire_y);
  520.           MoveWindow(hwnd_wire, Offset, Offset, wire_x,
  521.               wire_y, TRUE);
  522.           break;
  523.         case H_BMAP:
  524.           // Set scroll bar manager
  525.           pScroll->Set(Camera.GetWidth(),
  526.               Camera.GetHeight());
  527.           break;
  528.         default:
  529.           break;
  530.       }
  531.       break;
  532.     case WM_PAINT:      // Paint client area 
  533.       hdc = BeginPaint(hwnd, &ps);
  534.       if (DispType == H_BMAP)   // Display bitmap ?
  535.       {
  536.         GetClientRect(hwnd, &rc);
  537.         pos = pScroll->Pos();
  538.         if (Bitmap.Display(hdc, pos, rc) == FALSE)
  539.         {
  540.           DispType = H_NONE;
  541.           pScroll->Hide();
  542.           OutOfMemory();
  543.         }
  544.       }
  545.       EndPaint(hwnd, &ps);
  546.       break;
  547.     case WM_HSCROLL:    // Process horz scroll bar message
  548.       pScroll->Horz(GET_WM_HSCROLL_CODE(wparam, lparam),
  549.           GET_WM_HSCROLL_POS(wparam, lparam));
  550.       break;
  551.     case WM_VSCROLL:    // Process vertical scroll bar msg
  552.       pScroll->Vert(GET_WM_VSCROLL_CODE(wparam, lparam),
  553.           GET_WM_VSCROLL_POS(wparam, lparam));
  554.       break;
  555.     case WM_KEYDOWN:    // Process key down message
  556.       DoKeyDown(hwnd, wparam);
  557.       break;
  558.     case WM_LBUTTONDOWN:        // Process left button down
  559.       if (MoveType != H_LOCK && InCalc == FALSE)
  560.       {
  561.         // Save current mouse coordinates
  562.         mouse_x = LOWORD(lparam);
  563.         mouse_y = HIWORD(lparam);
  564.  
  565.         SetCapture(hwnd);       // Capture mouse input
  566.       }
  567.       break;
  568.     case WM_LBUTTONUP:          // Process left button up
  569.       if (MoveType != H_LOCK && InCalc == FALSE)
  570.       {
  571.         ReleaseCapture();   // Release mouse
  572.  
  573.         // Calculate mouse movement
  574.         mouse_dx = (int) LOWORD(lparam) - (int) mouse_x;
  575.         mouse_dy = (int) mouse_y - (int) HIWORD(lparam);
  576.  
  577.         switch (MoveType)   // Process camera movement
  578.         {
  579.           case H_DOLLY:
  580.             UpdateDolly(mouse_dy);
  581.             break;
  582.           case H_ORBIT:
  583.             UpdateOrbit(mouse_dx, mouse_dy);
  584.             break;
  585.           case H_PAN:
  586.             UpdatePan(mouse_dx, mouse_dy);
  587.             break;
  588.           case H_ROTATE:
  589.             UpdateRotate(mouse_dx, mouse_dy);
  590.             break;
  591.           case H_TILT:
  592.             UpdateTilt(mouse_dx);
  593.             break;
  594.           case H_ZOOM:
  595.             UpdateZoom(mouse_dy);
  596.             break;
  597.         }
  598.  
  599.         // Display wireframe
  600.         SendMessage(hwnd, WM_COMMAND, IDD_UPD_DISPLAY, 0L);
  601.       }
  602.       break;
  603.     case WM_RBUTTONDOWN:        // Process right button down
  604.       if (InCalc == FALSE)
  605.       {
  606.         // Get current mouse cursor coordinates
  607.         pos = MAKEPOINT(lparam);
  608.  
  609.         // Check whether mouse cursor is in client area
  610.         GetClientRect(hwnd, &rc);
  611.         if (PtInRect(&rc, pos) == TRUE)
  612.         {
  613.           // Convert mouse position to screen coordinates
  614.           ClientToScreen(hwnd, &pos);
  615.  
  616.           // Display Interactive popup menu
  617.           TrackPopupMenu(GetSubMenu(GetSubMenu(hmenu,
  618.               MENU_CAMERA_POS), MENU_INTERACTIVE_POS),
  619.               TPM_LEFTALIGN | TPM_LEFTBUTTON, pos.x, pos.y,
  620.               0, hwnd, NULL);
  621.         }
  622.       }
  623.       break;
  624.     case WM_QUERYENDSESSION:    // Terminate Windows session
  625.       if (InCalc == TRUE)
  626.       {
  627.         MessageBox(hwnd, CalcInProgress, AppName,
  628.             MB_ICONINFORMATION | MB_OK);
  629.         return NULL;
  630.       }
  631.       else
  632.         return 1L;
  633.     case WM_CLOSE:      // Terminate application
  634.       if (InCalc == TRUE)
  635.         MessageBox(hwnd, CalcInProgress, AppName,
  636.             MB_ICONINFORMATION | MB_OK);
  637.       else
  638.         DestroyWindow(hwnd);    // Close main window
  639.       break;
  640.     case WM_QUERYNEWPALETTE:    // New palette required ?
  641.     case WM_PALETTECHANGED:     // System palette changed
  642.       if (DispType == H_BMAP)
  643.         Bitmap.Redisplay(hwnd); // Redisplay bitmap
  644.       break;
  645.     case WM_COMMAND:    // Process window message
  646.       switch (GET_WM_COMMAND_ID(wparam, lparam))
  647.       {
  648.         case IDM_FILEOPEN:      // Open file
  649.           Ofn.lpstrDefExt = "WLD";
  650.           Ofn.lpstrFilter = InputFilterSpec;
  651.           Ofn.lpstrFile = WorldName;
  652.           Ofn.Flags = OFN_HIDEREADONLY | OFN_READONLY |
  653.               OFN_ENABLEHOOK;
  654.           Ofn.lpfnHook = (UINT (CALLBACK *)(HWND, UINT,
  655.               WPARAM, LPARAM)) MakeProcInstance((FARPROC)
  656.               FileOpenHook, hInst);
  657.           if (GetOpenFileName((LPOPENFILENAME) &Ofn))
  658.           {
  659.             switch (DispType)
  660.             {
  661.               case H_WIRE:
  662.                 // Erase wireframe metafile
  663.                 Wire.Erase();
  664.                 DispType = H_NONE;
  665.  
  666.                 // Close wireframe window
  667.                 DestroyWindow(hwnd_wire);
  668.                 break;
  669.               case H_BMAP:
  670.                 Bitmap.Close();     // Close bitmap
  671.                 DispType = H_NONE;
  672.                 pScroll->Hide();    // Hide scroll bars
  673.  
  674.                 // Disable Save As menu item
  675.                 EnableMenuItem(hmenu, IDM_SAVEAS,
  676.                     MF_GRAYED);
  677.  
  678.                 InvalidateRect(hwnd, NULL, TRUE);
  679.                 break;
  680.               default:
  681.                 break;
  682.             }
  683.  
  684.             // Display hourglass cursor
  685.             hcursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  686.  
  687.             // Parse environment file
  688.             if ((Parser.ParseFile(Ofn.lpstrFile, EntityDir,
  689.                 &Environment)) == TRUE)
  690.             {
  691.               // Update window title
  692.               wsprintf(StrBuffer, "HELIOS - %s",
  693.                   Ofn.lpstrFile);
  694.               SetWindowText(hwnd, StrBuffer);
  695.  
  696.               // Initialize camera view system
  697.               Camera.InitViewSystem(&Environment);
  698.  
  699.               // Display wireframe
  700.               SendMessage(hwnd, WM_COMMAND, IDM_WIREFRAME,
  701.                   0L);
  702.  
  703.               // Enable display statistics menu item
  704.               EnableMenuItem(hmenu, IDM_STATISTICS,
  705.                   MF_ENABLED);
  706.  
  707.               // Enable rendering menu items
  708.               EnableMenuItem(hmenu, IDM_WIREFRAME,
  709.                   MF_ENABLED);
  710.               EnableMenuItem(hmenu, IDM_SHADED,
  711.                   MF_ENABLED);
  712.               EnableMenuItem(hmenu, IDM_RENDER,
  713.                   MF_ENABLED);
  714.  
  715.               // Disable Redisplay menu item
  716.               EnableMenuItem(hmenu, IDM_REDISPLAY,
  717.                   MF_GRAYED);
  718.  
  719.               // Reset radiosity calculations done flag
  720.               RadCalcDone = FALSE;
  721.  
  722.               // Initialize camera view system
  723.               Camera.InitViewSystem(&Environment);
  724.             }
  725.  
  726.             SetCursor(hcursor);     // Redisplay old cursor
  727.           }
  728.           FreeProcInstance((FARPROC) Ofn.lpfnHook);
  729.           break;
  730.         case IDM_SAVEAS:        // Save BMP file
  731.           Ofn.lpstrDefExt = "BMP";
  732.           Ofn.lpstrFilter = OutputFilterSpec;
  733.           Ofn.lpstrFile = BitmapName;
  734.           Ofn.Flags = OFN_OVERWRITEPROMPT |
  735.               OFN_HIDEREADONLY;
  736.           if (GetSaveFileName((LPOPENFILENAME) &Ofn))
  737.           {
  738.             // Write bitmap file
  739.             switch (Ofn.nFilterIndex)
  740.             {
  741.               case 1:   // BMP format
  742.                 status = Bitmap.Write(Ofn.lpstrFile);
  743.                 break;
  744.               case 2:   // TARGA format
  745.                 status = Targa.Write(Bitmap.GetBitmapPtr(),
  746.                     Bitmap.GetPalettePtr(),
  747.                     Bitmap.GetWidth(), Bitmap.GetHeight(),
  748.                     Bitmap.GetScanWidth(),
  749.                     Bitmap.GetNumColors(),
  750.                     Ofn.lpstrFile);
  751.                 break;
  752.               default:  // Unrecognized format
  753.                 status = FALSE;
  754.                 break;
  755.             }
  756.  
  757.             if (status == FALSE)        // Check for error
  758.             {
  759.               sprintf(StrBuffer, "Could not save file %s",
  760.                   Ofn.lpstrFile);
  761.                 ReportError(StrBuffer);
  762.             }
  763.           }
  764.           break;
  765.         case IDM_EXIT:          // Exit application
  766.           DestroyWindow(hwnd);
  767.           break;
  768.         case IDM_SETCAMERA:     // Set camera parameters
  769.           if (hSetCameraDlg == NULL)
  770.             hSetCameraDlg = CreateDialog(hInst, "SetCamera",
  771.                 hwnd, (DLGPROC) pcfunc);
  772.           break;
  773.         case IDM_SETVIEW:       // Specify view direction
  774.           if (hSetViewDlg == NULL)
  775.             hSetViewDlg = CreateDialog(hInst, "SetView",
  776.                 hwnd, (DLGPROC) pvfunc);
  777.           break;
  778.         case IDM_SETDOLLY:      // Toggle camera dolly
  779.         case IDM_SETORBIT:      // Toggle camera orbit
  780.         case IDM_SETPAN:        // Toggle camera pan
  781.         case IDM_SETROTATE:     // Toggle camera rotate
  782.         case IDM_SETTILT:       // Toggle camera tilt
  783.         case IDM_SETZOOM:       // Toggle camera zoom
  784.           SetMovementType(hmenu, GET_WM_COMMAND_ID(wparam,
  785.               lparam));
  786.           break;
  787.         case IDM_DEFVIEW:       // Display default view
  788.           // Initialize camera view system
  789.           Camera.InitViewSystem(&Environment);
  790.  
  791.           // Update modeless Camera Parameters dialog box
  792.           UpdateCameraDialog();
  793.  
  794.           // Update modeless View Parameters dialog box
  795.           UpdateViewDialog();
  796.  
  797.           // Display wireframe
  798.           SendMessage(hwnd, WM_COMMAND, IDD_UPD_DISPLAY,
  799.               0L);
  800.           break;  
  801.         case IDM_WIREFRAME:     // Wireframe display
  802.           if (DispType != H_WIRE)
  803.           {
  804.             if (DispType == H_BMAP)
  805.             {
  806.               Bitmap.Close();       // Close bitmap
  807.               DispType = H_NONE;
  808.               pScroll->Hide();      // Hide scroll bars
  809.  
  810.               // Disable Save As menu item
  811.               EnableMenuItem(hmenu, IDM_SAVEAS, MF_GRAYED);
  812.  
  813.               InvalidateRect(hwnd, NULL, TRUE);
  814.             }
  815.  
  816.             // Create wireframe window
  817.             CalcWireDim(client_x, client_y, &wire_x,
  818.                 &wire_y);
  819.             hwnd_wire = CreateWindow(WireClass, NULL,
  820.                 WS_CHILD | WS_VISIBLE | WS_BORDER |
  821.                 WS_DISABLED, Offset, Offset, wire_x, wire_y,
  822.                     hwnd, NULL, hInst, NULL);
  823.             DispType = H_WIRE;
  824.  
  825.             // Record wireframe display
  826.             if (Camera.Preview(&Environment, &Wire) ==
  827.                 FALSE)
  828.               OutOfMemory();
  829.           }
  830.           break;
  831.         case IDM_SHADED:        // Shaded display
  832.         case IDM_RENDER:        // Radiosity rendering
  833.           if (wparam == IDM_RENDER)
  834.           {
  835.             DisableMenu(hmenu);     // Disable menu items
  836.  
  837.             // Reset radiosity calculations done flag
  838.             RadCalcDone = FALSE;
  839.  
  840.             // Confirm radiosity equation solver status
  841.             if (Radiosity.GetStatus() == FALSE)
  842.             {
  843.               OutOfMemory();
  844.               EnableMenu(hmenu);    // Enable menu items
  845.               break;
  846.             }
  847.  
  848.             // Initialize equation solver
  849.             if (Radiosity.Open(&Environment) == FALSE)
  850.             {
  851.               OutOfMemory();
  852.               EnableMenu(hmenu);    // Enable menu items
  853.               break;
  854.             }
  855.  
  856.             // Create modeless radiosity calculations
  857.             // dialog box
  858.             InCalc = TRUE;
  859.             pfunc = (DLGPROC) MakeProcInstance((FARPROC)
  860.                 AbortCalc, hInst);
  861.             hAbortDlg = CreateDialog(hInst, "AbortRad",
  862.                 hwnd, (DLGPROC) pfunc);
  863.             SetDlgItemInt(hAbortDlg, IDC_MAXSTEP,
  864.                 Radiosity.GetMaxStep(), FALSE);
  865.             SetDlgItemFloat(hAbortDlg, IDC_MINSTOP,
  866.                 Radiosity.GetStopCriterion());
  867.  
  868.             // Perform radiosity calculations
  869.             while (Radiosity.Calculate() == FALSE)
  870.             {
  871.               // Check for user-requested abort
  872.               if (CheckAbort() == TRUE)
  873.               {
  874.                 AbortFlag = FALSE;
  875.                 break;
  876.               }
  877.  
  878.               // Display radiosity calculations progress
  879.               SetDlgItemInt(hAbortDlg, IDC_NUMSTEP,
  880.                   Radiosity.GetStepCount(), FALSE);
  881.               SetDlgItemFloat(hAbortDlg, IDC_CONVERGE,
  882.                   Radiosity.GetConvergence());
  883.               SetDlgItemText(hAbortDlg, IDC_ELAPSED,
  884.                   Radiosity.GetElapsedTime());
  885.             }
  886.  
  887.             // Close radiosity calculations dialog box
  888.             DestroyWindow(hAbortDlg);
  889.             FreeProcInstance((FARPROC) pfunc);
  890.             UpdateWindow(hwnd);
  891.  
  892.             // Close radiosity equation solver
  893.             Radiosity.Close();
  894.  
  895.             InCalc = FALSE;
  896.             if (AbortFlag == FALSE)
  897.             {
  898.               // Set radiosity calculations done flag
  899.               RadCalcDone = TRUE;
  900.             }
  901.  
  902.             EnableMenu(hmenu);  // Enable menu items
  903.           }
  904.           else
  905.           {
  906.             // Set vertice exitances to parent surface
  907.             // reflectances
  908.             Radiosity.Shade(&Environment);
  909.  
  910.             // Reset radiosity calculations done flag
  911.             RadCalcDone = FALSE;
  912.           }
  913.   
  914.           // Open new bitmap
  915.           if (Bitmap.Open(Camera.GetWidth(),
  916.               Camera.GetHeight()) == TRUE)
  917.           {
  918.             // Display bitmap
  919.             if (DisplayBitmap(hwnd, hwnd_wire, hmenu) ==
  920.                 TRUE)
  921.             {
  922.               if (wparam == IDM_RENDER)
  923.               {
  924.                 MessageBeep(MB_OK);     // Signal completion
  925.  
  926.                 // Display convergence statistics
  927.                 sprintf(StrBuffer, "Number of Steps = %d\n"
  928.                     "Convergence = %f\nElapsed Time = %s",
  929.                 Radiosity.GetStepCount(),
  930.                 Radiosity.GetConvergence(),
  931.                 Radiosity.GetElapsedTime());
  932.  
  933.                 MessageBox(hwnd, StrBuffer, "Convergence "
  934.                     "Statistics", MB_OK |
  935.                     MB_ICONINFORMATION);
  936.  
  937.                 // Disable Rendering menu item
  938.                 EnableMenuItem(hmenu, IDM_RENDER,
  939.                     MF_GRAYED);
  940.               }
  941.             }
  942.             else
  943.               Bitmap.Close();   // Close bitmap
  944.           }
  945.           else
  946.             OutOfMemory();      // Report error
  947.           break;
  948.         case IDM_REDISPLAY:     // Redisplay bitmap
  949.           if (DispType == H_BMAP)
  950.             Bitmap.Close();     // Close bitmap
  951.  
  952.           // Open new bitmap
  953.           if (Bitmap.Open(Camera.GetWidth(),
  954.               Camera.GetHeight()) == TRUE)
  955.           {
  956.             // Display bitmap
  957.             if (DisplayBitmap(hwnd, hwnd_wire, hmenu) ==
  958.                 FALSE)
  959.               Bitmap.Close();   // Close bitmap
  960.           }
  961.           else
  962.             OutOfMemory();
  963.           break;
  964.         case IDD_UPD_DISPLAY:   // Update display
  965.           if (DispType == H_BMAP)
  966.           {
  967.             Bitmap.Close();     // Close bitmap
  968.  
  969.             // Open new bitmap
  970.             if (Bitmap.Open(Camera.GetWidth(),
  971.                 Camera.GetHeight()) == TRUE)
  972.             {
  973.               // Display bitmap
  974.               if (DisplayBitmap(hwnd, hwnd_wire, hmenu) ==
  975.                   FALSE)
  976.                 Bitmap.Close(); // Close bitmap
  977.             }
  978.             else
  979.               OutOfMemory();    // Report error
  980.           }
  981.           else if (DispType == H_WIRE)
  982.           {
  983.             // Record wireframe display
  984.             if (Camera.Preview(&Environment, &Wire) ==
  985.                 TRUE)
  986.             {
  987.               // Resize and redraw wireframe window
  988.               InvalidateRect(hwnd_wire, NULL, TRUE);
  989.               CalcWireDim(client_x, client_y, &wire_x,
  990.                   &wire_y);
  991.               MoveWindow(hwnd_wire, Offset, Offset, wire_x,
  992.                   wire_y, TRUE);
  993.             }
  994.             else
  995.               OutOfMemory();
  996.           }
  997.           break;
  998.         case IDM_DIRECTORY:     // Set entity directory
  999.           pfunc = (DLGPROC) MakeProcInstance((FARPROC)
  1000.               SetEntityDir, hInst);
  1001.           DialogBox(hInst, "SetEntityDir", hwnd, pfunc);
  1002.           FreeProcInstance((FARPROC) pfunc);
  1003.           break;
  1004.         case IDM_STATISTICS:    // Display statistics
  1005.           pfunc = (DLGPROC) MakeProcInstance((FARPROC)
  1006.               DisplayStats, hInst);
  1007.           DialogBox(hInst, "DisplayStats", hwnd, pfunc);
  1008.           FreeProcInstance((FARPROC) pfunc);
  1009.           break;
  1010.         case IDM_SETCONVERGE:   // Set convergence
  1011.           pfunc = (DLGPROC) MakeProcInstance((FARPROC)
  1012.               SetConverge, hInst);
  1013.           redraw = DialogBox(hInst, "SetConverge", hwnd,
  1014.               pfunc);
  1015.           FreeProcInstance((FARPROC) pfunc);
  1016.           if (redraw == TRUE)
  1017.           {
  1018.             // Reset radiosity calculations done flag
  1019.             RadCalcDone = FALSE;
  1020.  
  1021.             // Enable Rendering menu item
  1022.             EnableMenuItem(hmenu, IDM_RENDER, MF_ENABLED);
  1023.           }
  1024.           break;
  1025.         case IDM_SETDISPLAY:    // Set display parameters
  1026.           if (hSetDisplayDlg == NULL)
  1027.             hSetDisplayDlg = CreateDialog(hInst,
  1028.                 "SetDisplay", hwnd, (DLGPROC) pdfunc);
  1029.           break;
  1030.         case IDM_SETCOLOR:      // Set color parameters
  1031.           if (hSetColorDlg == NULL)
  1032.             hSetColorDlg = CreateDialog(hInst, "SetColor",
  1033.                 hwnd, (DLGPROC) pofunc);
  1034.           break;
  1035.         case IDM_HELP_CONTENTS: // Display Help contents
  1036.            WinHelp(hwnd, HelpFileName, HELP_CONTENTS, 0L);
  1037.            break;
  1038.         case IDM_HELP_HELP:     // Display Using Help
  1039.           WinHelp(hwnd, "WINHELP.HLP", HELP_CONTENTS, 0L);
  1040.           break;
  1041.         case IDM_HELP_BOOK:     // Display book info
  1042.           WinHelp(hwnd, HelpFileName, HELP_CONTEXT,
  1043.               (DWORD) HELP_BOOK);
  1044.           break;
  1045.         case IDM_ABOUT:         // Display About box
  1046.           pfunc = (DLGPROC) MakeProcInstance((FARPROC)
  1047.               About, hInst);
  1048.           DialogBox(hInst, "AboutBox", hwnd, pfunc);
  1049.           FreeProcInstance((FARPROC) pfunc);
  1050.           break;
  1051.         default:
  1052.           break;
  1053.       }
  1054.       break;
  1055.     case WM_DESTROY:    // Destroy window
  1056.       delete pScroll;   // Delete scroll bar manager
  1057.       Wire.Erase();     // Erase wireframe metafile
  1058.       Bitmap.Close();   // Release bitmap memory
  1059.  
  1060.       // Cancel Windows Help
  1061.       WinHelp(hwnd, HelpFileName, HELP_QUIT, 0L);
  1062.  
  1063.       // Release dialog box procedure instance thunks
  1064.       FreeProcInstance((FARPROC) pcfunc);
  1065.       FreeProcInstance((FARPROC) pdfunc);
  1066.       FreeProcInstance((FARPROC) pvfunc);
  1067.  
  1068.       PostQuitMessage(0);
  1069.       break;
  1070.     default:
  1071.       return DefWindowProc(hwnd, msg, wparam, lparam);
  1072.   }
  1073.   return NULL;
  1074. }
  1075.  
  1076. // File Open dialog box hook function
  1077. UINT CALLBACK FileOpenHook( HWND hdlg, UINT msg, WPARAM
  1078.     wparam, LPARAM lParam)
  1079. {
  1080.   if (msg == WM_INITDIALOG)
  1081.   {
  1082.     CenterDialog(hdlg);
  1083.     return TRUE;
  1084.   }
  1085.   else
  1086.     return FALSE;
  1087. }
  1088.  
  1089. // Wireframe window message handler
  1090. LRESULT WINAPI WireWndProc( HWND hwnd, UINT msg, WPARAM
  1091.     wparam, LPARAM lparam )
  1092. {
  1093.   static short client_x;    // Client area width
  1094.   static short client_y;    // Client area height
  1095.  
  1096.   switch (msg)
  1097.   {
  1098.     case WM_SIZE:
  1099.       client_x = LOWORD(lparam);
  1100.       client_y = HIWORD(lparam);
  1101.       break;
  1102.     case WM_PAINT:      // Paint client area
  1103.       Wire.Play(hwnd, Camera.GetWidth(), Camera.GetHeight(),
  1104.           client_x, client_y);
  1105.       break;
  1106.     default:
  1107.       return DefWindowProc(hwnd, msg, wparam, lparam);
  1108.   }
  1109.   return NULL;
  1110. }
  1111.  
  1112. // Set entities directory
  1113. BOOL CALLBACK SetEntityDir( HWND hdlg, UINT msg, WPARAM
  1114.     wparam, LPARAM lparam )
  1115. {
  1116.   switch (msg)
  1117.   {
  1118.     case WM_INITDIALOG:
  1119.       SetDlgItemText(hdlg, IDC_ENTITY, EntityDir);
  1120.       CenterDialog(hdlg);
  1121.       return TRUE;
  1122.     case WM_COMMAND:
  1123.       switch (GET_WM_COMMAND_ID(wparam, lparam))
  1124.       {
  1125.         case IDC_HELP_SETDIR:   // Display Help
  1126.           WinHelp(hdlg, HelpFileName, HELP_CONTEXT,
  1127.               (DWORD) HELP_SETDIR);
  1128.           break;
  1129.         case IDOK:
  1130.           GetDlgItemText(hdlg, IDC_ENTITY, EntityDir,
  1131.               sizeof(EntityDir));
  1132.           EndDialog(hdlg, TRUE);
  1133.           return TRUE;
  1134.         case IDCANCEL:
  1135.           EndDialog(hdlg, FALSE);
  1136.           return TRUE;
  1137.         default:
  1138.           break;
  1139.       }
  1140.       break;
  1141.     default:
  1142.       break;
  1143.   }
  1144.   return FALSE;
  1145. }
  1146.  
  1147. // Display environment statistics
  1148. BOOL CALLBACK DisplayStats( HWND hdlg, UINT msg, WPARAM
  1149.     wparam, LPARAM lparam )
  1150. {
  1151.   switch (msg)
  1152.   {
  1153.     case WM_INITDIALOG:
  1154.       // Initialize environment statistics
  1155.       SetDlgItemInt(hdlg, IDC_NUM_INSTANCES,
  1156.           Environment.GetNumInst(), FALSE);
  1157.       SetDlgItemInt(hdlg, IDC_NUM_SURFACES,
  1158.           Environment.GetNumSurf(), FALSE);
  1159.       SetDlgItemInt(hdlg, IDC_NUM_PATCHES,
  1160.           Environment.GetNumPatch(), FALSE);
  1161.       SetDlgItemInt(hdlg, IDC_NUM_ELEMENTS,
  1162.           Environment.GetNumElem(), FALSE);
  1163.       SetDlgItemInt(hdlg, IDC_NUM_VERTICES,
  1164.           Environment.GetNumVert(), FALSE);
  1165.  
  1166.       CenterDialog(hdlg);
  1167.       return TRUE;
  1168.     case WM_COMMAND:
  1169.       switch (GET_WM_COMMAND_ID(wparam, lparam))
  1170.       {
  1171.         case IDOK:
  1172.           EndDialog(hdlg, TRUE);
  1173.           return TRUE;
  1174.         default:
  1175.           break;
  1176.       }
  1177.       break;
  1178.     default:
  1179.       break;
  1180.   }
  1181.   return FALSE;
  1182. }
  1183.  
  1184. // Set camera parameters
  1185. BOOL CALLBACK SetCamera( HWND hdlg, UINT msg, WPARAM
  1186.     wparam, LPARAM lparam )
  1187. {
  1188.   double vpd, fpd, bpd;     // Camera distances
  1189.   double scale;             // Window scaling factor
  1190.   double tilt;              // Camera tilt angle
  1191.   int w, h;                 // Bitmap window dimensions
  1192.   BOOL dummy;               // Dummy parameter
  1193.   static BOOL par_flag;     // Parallel projection flag
  1194.  
  1195.   switch (msg)
  1196.   {
  1197.     case WM_INITDIALOG:
  1198.       // Get camera distances
  1199.       SetDlgItemFloat(hdlg, IDC_VDIST,
  1200.           Camera.GetViewDist());
  1201.       SetDlgItemFloat(hdlg, IDC_FDIST,
  1202.           Camera.GetFrontDist());
  1203.       SetDlgItemFloat(hdlg, IDC_BDIST,
  1204.           Camera.GetBackDist());
  1205.  
  1206.       // Get window scaling factor
  1207.       SetDlgItemFloat(hdlg, IDC_SCALE,
  1208.           Camera.GetWindowScale());
  1209.  
  1210.       // Get bitmap window dimensions
  1211.       SetDlgItemInt(hdlg, IDC_HPIXSZ, Camera.GetWidth(),
  1212.           FALSE);
  1213.       SetDlgItemInt(hdlg, IDC_VPIXSZ, Camera.GetHeight(),
  1214.           FALSE);
  1215.  
  1216.       // Get camera tilt angle
  1217.       SetDlgItemFloat(hdlg, IDC_CAMTILT,
  1218.           RadToDeg(Camera.GetTiltAngle()));
  1219.  
  1220.       // Get projection type
  1221.       par_flag = Camera.GetParProjFlag();
  1222.  
  1223.       if (par_flag == TRUE)
  1224.         CheckRadioButton(hdlg, IDC_PERSPECT, IDC_PARALLEL,
  1225.             IDC_PARALLEL);
  1226.       else
  1227.         CheckRadioButton(hdlg, IDC_PERSPECT, IDC_PARALLEL,
  1228.             IDC_PERSPECT);
  1229.  
  1230.       CenterDialog(hdlg);
  1231.       return TRUE;
  1232.     case WM_COMMAND:
  1233.       switch (GET_WM_COMMAND_ID(wparam, lparam))
  1234.       {
  1235.         case IDC_PERSPECT:
  1236.         case IDC_PARALLEL:
  1237.           par_flag = (wparam - IDC_PERSPECT != 0) ? TRUE :
  1238.               FALSE;
  1239.  
  1240.           CheckRadioButton(hdlg, IDC_PERSPECT, IDC_PARALLEL,
  1241.               wparam);
  1242.           break;
  1243.         case IDC_HELP_SETCAMERA:        // Display Help
  1244.           WinHelp(hdlg, HelpFileName, HELP_CONTEXT,
  1245.               (DWORD) HELP_SETCAMERA);
  1246.           break;
  1247.         case IDOK:
  1248.         case IDC_UPDATE:
  1249.           // Validate distances
  1250.           vpd = GetDlgItemFloat(hdlg, IDC_VDIST);
  1251.           fpd = GetDlgItemFloat(hdlg, IDC_FDIST);
  1252.           bpd = GetDlgItemFloat(hdlg, IDC_BDIST);
  1253.  
  1254.           if (vpd <= 0.0)
  1255.           {
  1256.             MessageBox(hdlg, ViewDistError, AppName,
  1257.                 MB_ICONEXCLAMATION | MB_OK);
  1258.             return FALSE;
  1259.           }
  1260.  
  1261.           if (fpd >= bpd)
  1262.           {
  1263.             MessageBox(hdlg, FrontDistError, AppName,
  1264.                 MB_ICONEXCLAMATION | MB_OK);
  1265.             return FALSE;
  1266.           }
  1267.  
  1268.           if (fpd < -(vpd - MIN_VALUE))
  1269.           {
  1270.             MessageBox(hdlg, EyeDistError, AppName,
  1271.                 MB_ICONEXCLAMATION | MB_OK);
  1272.             return FALSE;
  1273.           }
  1274.  
  1275.           // Validate window scaling factor
  1276.           scale = GetDlgItemFloat(hdlg, IDC_SCALE);
  1277.  
  1278.           if (scale <= 0.0)
  1279.           {
  1280.             MessageBox(hdlg, WindowScaleError, AppName,
  1281.                 MB_ICONEXCLAMATION | MB_OK);
  1282.             return FALSE;
  1283.           }
  1284.  
  1285.           // Validate bitmap window dimensions
  1286.           w = (int) GetDlgItemInt(hdlg, IDC_HPIXSZ, &dummy,
  1287.               FALSE);
  1288.           h = (int) GetDlgItemInt(hdlg, IDC_VPIXSZ, &dummy,
  1289.               FALSE);
  1290.  
  1291.           if (w < MinPixel || w > MaxPixel || h < MinPixel
  1292.               || h > MaxPixel)
  1293.           {
  1294.             MessageBox(hdlg, PixelError, AppName,
  1295.                 MB_ICONEXCLAMATION | MB_OK);
  1296.             return FALSE;
  1297.           }
  1298.  
  1299.           // Validate tilt angle
  1300.           tilt = GetDlgItemFloat(hdlg, IDC_CAMTILT);
  1301.  
  1302.           if (tilt < 0.0 || tilt > 360.0)
  1303.           {
  1304.             MessageBox(hdlg, TiltError, AppName,
  1305.                 MB_ICONEXCLAMATION | MB_OK);
  1306.             return FALSE;
  1307.           }
  1308.  
  1309.           // Set distances
  1310.           Camera.SetViewDist(vpd);
  1311.           Camera.SetFrontDist(fpd);
  1312.           Camera.SetBackDist(bpd);
  1313.  
  1314.           // Set window scaling factor
  1315.           Camera.SetWindowScale(scale);
  1316.  
  1317.           // Set bitmap window dimensions
  1318.           Camera.SetWidth(w);
  1319.           Camera.SetHeight(h);
  1320.  
  1321.           // Set camera tilt angle
  1322.           Camera.SetTiltAngle(DegToRad(tilt));
  1323.  
  1324.           // Set projection type
  1325.           Camera.SetParProjFlag(par_flag);
  1326.  
  1327.           // Update view system parameters
  1328.           Camera.UpdateViewSystem();
  1329.  
  1330.           // Instruct parent window to update client area
  1331.           SendMessage(GetParent(hdlg), WM_COMMAND,
  1332.               IDD_UPD_DISPLAY, 0L);
  1333.  
  1334.           if (GET_WM_COMMAND_ID(wparam, lparam) == IDOK)
  1335.           {
  1336.             DestroyWindow(hdlg);        // Close dialog box
  1337.             hSetCameraDlg = NULL;
  1338.           }
  1339.  
  1340.           return TRUE;
  1341.         case IDCANCEL:
  1342.           DestroyWindow(hdlg);          // Close dialog box
  1343.           hSetCameraDlg = NULL;
  1344.           return TRUE;
  1345.         default:
  1346.           break;
  1347.       }
  1348.       break;
  1349.     case WM_CLOSE:
  1350.       DestroyWindow(hdlg);      // Close dialog box
  1351.       hSetCameraDlg = NULL;
  1352.       return TRUE;
  1353.     default:
  1354.       break;
  1355.   }
  1356.   return FALSE;
  1357. }
  1358.  
  1359. // Set camera view parameters
  1360. BOOL CALLBACK SetView( HWND hdlg, UINT msg, WPARAM
  1361.     wparam, LPARAM lparam )
  1362. {
  1363.   Point3 eye_posn;      // Camera eye position
  1364.   Point3 focus_posn;    // Camera focus position
  1365.   Vector3 temp;         // Temporary vector
  1366.   Vector3 view_dir;     // View direction vector
  1367.   Vector3 view_up;      // View-up vector
  1368.  
  1369.   switch (msg)
  1370.   {
  1371.     case WM_INITDIALOG:
  1372.       // Get camera eye position
  1373.       eye_posn = Camera.GetEyePosn();
  1374.       SetDlgItemFloat(hdlg, IDC_EYE_X, eye_posn.GetX());
  1375.       SetDlgItemFloat(hdlg, IDC_EYE_Y, eye_posn.GetY());
  1376.       SetDlgItemFloat(hdlg, IDC_EYE_Z, eye_posn.GetZ());
  1377.  
  1378.       // Get camera focus position
  1379.       focus_posn = Camera.GetFocusPosn();
  1380.       SetDlgItemFloat(hdlg, IDC_FOCUS_X, focus_posn.GetX());
  1381.       SetDlgItemFloat(hdlg, IDC_FOCUS_Y, focus_posn.GetY());
  1382.       SetDlgItemFloat(hdlg, IDC_FOCUS_Z, focus_posn.GetZ());
  1383.  
  1384.       CenterDialog(hdlg);
  1385.       return TRUE;
  1386.     case WM_COMMAND:
  1387.       switch (GET_WM_COMMAND_ID(wparam, lparam))
  1388.       {
  1389.         case IDC_HELP_SETVIEW:  // Display Help
  1390.           WinHelp(hdlg, HelpFileName, HELP_CONTEXT,
  1391.               (DWORD) HELP_SETVIEW);
  1392.           break;
  1393.         case IDOK:
  1394.         case IDC_UPDATE:
  1395.           // Get eye position
  1396.           eye_posn.SetX(GetDlgItemFloat(hdlg, IDC_EYE_X));
  1397.           eye_posn.SetY(GetDlgItemFloat(hdlg, IDC_EYE_Y));
  1398.           eye_posn.SetZ(GetDlgItemFloat(hdlg, IDC_EYE_Z));
  1399.  
  1400.           // Get focus position
  1401.           focus_posn.SetX(GetDlgItemFloat(hdlg,
  1402.               IDC_FOCUS_X));
  1403.           focus_posn.SetY(GetDlgItemFloat(hdlg,
  1404.               IDC_FOCUS_Y));
  1405.           focus_posn.SetZ(GetDlgItemFloat(hdlg,
  1406.               IDC_FOCUS_Z));
  1407.  
  1408.           // Validate eye and focus positions
  1409.           temp = Vector3(eye_posn, focus_posn);
  1410.           if (fabs(temp.Length()) < MIN_VALUE)
  1411.           {
  1412.             MessageBox(hdlg, FocusError, AppName,
  1413.                 MB_ICONEXCLAMATION | MB_OK);
  1414.             return FALSE;
  1415.           }
  1416.  
  1417.           // Set camera view parameters
  1418.           Camera.SetEyeFocusPosn(eye_posn, focus_posn);
  1419.  
  1420.           // Update view system parameters
  1421.           Camera.UpdateViewSystem();
  1422.  
  1423.           // Instruct parent window to update client area
  1424.           SendMessage(GetParent(hdlg), WM_COMMAND,
  1425.               IDD_UPD_DISPLAY, 0L);
  1426.               
  1427.           if (GET_WM_COMMAND_ID(wparam, lparam) == IDOK)
  1428.           {
  1429.             DestroyWindow(hdlg);        // Close dialog box
  1430.             hSetViewDlg = NULL;
  1431.           }
  1432.  
  1433.           return TRUE;
  1434.         case IDCANCEL:
  1435.           DestroyWindow(hdlg);          // Close dialog box
  1436.           hSetViewDlg = NULL;
  1437.           return TRUE;
  1438.         default:
  1439.           break;
  1440.       }
  1441.       break;
  1442.     case WM_CLOSE:
  1443.       DestroyWindow(hdlg);      // Close dialog box
  1444.       hSetViewDlg = NULL;
  1445.       return TRUE;
  1446.     default:
  1447.       break;
  1448.   }
  1449.   return FALSE;
  1450. }
  1451.  
  1452. // Set radiosity rendering convergence parameters
  1453. BOOL CALLBACK SetConverge( HWND hdlg, UINT msg, WPARAM
  1454.     wparam, LPARAM lparam )
  1455. {
  1456.   int mp;       // Maximum number of steps
  1457.   double sc;    // Stopping criterion
  1458.   BOOL dummy;   // Dummy parameter
  1459.  
  1460.   switch (msg)
  1461.   {
  1462.     case WM_INITDIALOG:
  1463.       SetDlgItemInt(hdlg, IDC_MSTEP, Radiosity.GetMaxStep(),
  1464.           FALSE);
  1465.       SetDlgItemFloat(hdlg, IDC_STOPC,
  1466.           Radiosity.GetStopCriterion());
  1467.       CheckDlgButton(hdlg, IDC_AMBIENT_EN,
  1468.           Radiosity.AmbientFlag());
  1469.  
  1470.       if (Radiosity.OverShootFlag() == TRUE)
  1471.         CheckDlgButton(hdlg, IDC_OVER_EN, TRUE);
  1472.  
  1473.       CenterDialog(hdlg);
  1474.       return TRUE;
  1475.     case WM_COMMAND:
  1476.       switch (GET_WM_COMMAND_ID(wparam, lparam))
  1477.       {
  1478.         case IDC_HELP_SETCONVERGE:      // Display Help
  1479.           WinHelp(hdlg, HelpFileName, HELP_CONTEXT,
  1480.               (DWORD) HELP_SETCONVERGE);
  1481.           break;
  1482.         case IDOK:
  1483.           // Validate parameters
  1484.           mp = GetDlgItemInt(hdlg, IDC_MSTEP, &dummy, TRUE);
  1485.           sc = GetDlgItemFloat(hdlg, IDC_STOPC);
  1486.  
  1487.           if (mp < 1 || mp > MaxStep)
  1488.           {
  1489.             MessageBox(hdlg, MaxStepError, AppName,
  1490.                 MB_ICONEXCLAMATION | MB_OK);
  1491.             return FALSE;
  1492.           }
  1493.  
  1494.           if (sc <= 0.0 || sc > 1.0)
  1495.           {
  1496.             MessageBox(hdlg, StopError, AppName,
  1497.                 MB_ICONEXCLAMATION | MB_OK);
  1498.             return FALSE;
  1499.           }
  1500.  
  1501.           // Set convergence parameters
  1502.           Radiosity.SetMaxStep(mp);
  1503.           Radiosity.SetStopCriterion(sc);
  1504.  
  1505.           if (IsDlgButtonChecked(hdlg, IDC_AMBIENT_EN) != 0)
  1506.             Radiosity.EnableAmbient();
  1507.           else
  1508.             Radiosity.DisableAmbient();
  1509.  
  1510.           if (IsDlgButtonChecked(hdlg, IDC_OVER_EN) != 0)
  1511.             Radiosity.EnableOverShoot();
  1512.           else
  1513.             Radiosity.DisableOverShoot();
  1514.  
  1515.           EndDialog(hdlg, TRUE);
  1516.           return TRUE;
  1517.         case IDCANCEL:
  1518.           EndDialog(hdlg, FALSE);
  1519.           return TRUE;
  1520.         default:
  1521.           break;
  1522.       }
  1523.       break;
  1524.     default:
  1525.       break;
  1526.   }
  1527.   return FALSE;
  1528. }
  1529.  
  1530. // Set display parameters
  1531. BOOL CALLBACK SetDisplay( HWND hdlg, UINT msg, WPARAM
  1532.     wparam, LPARAM lparam )
  1533. {
  1534.   int i;                // Loop index
  1535.   int noise;            // Noise parameter
  1536.   double contrast;      // Contrast value
  1537.   double gamma;         // Gamma parameter
  1538.   double intensity;     // Intensity value
  1539.   BOOL dummy;           // Dummy parameter
  1540.  
  1541.   switch (msg)
  1542.   {
  1543.     case WM_INITDIALOG:
  1544.       SetDlgItemFloat(hdlg, IDC_INTENS,
  1545.           Camera.GetIntensity());
  1546.       SetDlgItemFloat(hdlg, IDC_CONTRAST,
  1547.           Camera.GetContrast());
  1548.       SetDlgItemFloat(hdlg, IDC_GAMMA, Camera.GetGamma());
  1549.       SetDlgItemInt(hdlg, IDC_JITTER,
  1550.           Camera.GetNoiseLevel(), FALSE);
  1551.       CheckDlgButton(hdlg, IDC_INTENS_EN,
  1552.           Camera.IntensityFlag());
  1553.       CheckDlgButton(hdlg, IDC_CONTRAST_EN,
  1554.           Camera.ContrastFlag());
  1555.       CheckDlgButton(hdlg, IDC_GAMMA_EN,
  1556.           Camera.GammaFlag());
  1557.       CheckDlgButton(hdlg, IDC_JITTER_EN,
  1558.           Camera.JitterFlag());
  1559.  
  1560.       // Initialize filter selection combo box
  1561.       for (i = 0; i < Camera.GetNumFilters(); i++)
  1562.         SendDlgItemMessage(hdlg, IDC_FILTERSEL,
  1563.             CB_INSERTSTRING, i, (LPARAM)
  1564.             Camera.GetFilterSize(i));
  1565.  
  1566.       // Select current antialiasing filter
  1567.       (void) SendDlgItemMessage(hdlg, IDC_FILTERSEL,
  1568.           CB_SELECTSTRING, -1, (LONG)
  1569.           Camera.GetCurrFilterSize());
  1570.  
  1571.       CenterDialog(hdlg);
  1572.       return TRUE;
  1573.     case WM_COMMAND:
  1574.       switch (GET_WM_COMMAND_ID(wparam, lparam))
  1575.       {
  1576.         case IDC_HELP_SETDISPLAY:       // Display Help
  1577.           WinHelp(hdlg, HelpFileName, HELP_CONTEXT,
  1578.               (DWORD) HELP_SETDISPLAY);
  1579.           break;
  1580.         case IDOK:
  1581.         case IDC_UPDATE:
  1582.           intensity = GetDlgItemFloat(hdlg, IDC_INTENS);
  1583.  
  1584.           // Set intensity parameter
  1585.           Camera.SetIntensity(intensity);
  1586.  
  1587.           contrast = GetDlgItemFloat(hdlg, IDC_CONTRAST);
  1588.  
  1589.           if (contrast <= 0.0)
  1590.           {
  1591.             MessageBox(hdlg, ContrastError, AppName,
  1592.                 MB_ICONEXCLAMATION | MB_OK);
  1593.             return FALSE;
  1594.           }
  1595.  
  1596.           // Set contrast parameter
  1597.           Camera.SetContrast(contrast);
  1598.  
  1599.           gamma = GetDlgItemFloat(hdlg, IDC_GAMMA);
  1600.  
  1601.           if (gamma <= 0.0)
  1602.           {
  1603.             MessageBox(hdlg, GammaError, AppName,
  1604.                 MB_ICONEXCLAMATION | MB_OK);
  1605.             return FALSE;
  1606.           }
  1607.  
  1608.           // Set gamma correction parameter
  1609.           Camera.SetGamma(gamma);
  1610.  
  1611.           noise = GetDlgItemInt(hdlg, IDC_JITTER, &dummy,
  1612.               TRUE);
  1613.  
  1614.           if (noise < 0 || noise > 8)
  1615.           {
  1616.             MessageBox(hdlg, NoiseError, AppName,
  1617.                 MB_ICONEXCLAMATION | MB_OK);
  1618.             return FALSE;
  1619.           }
  1620.  
  1621.           // Set noise level parameter
  1622.           Camera.SetNoiseLevel(noise);
  1623.  
  1624.           // Set antialiasing filter type
  1625.           Camera.SetFilterType((int)
  1626.               SendDlgItemMessage(hdlg, IDC_FILTERSEL,
  1627.               CB_GETCURSEL, 0, 0L));
  1628.  
  1629.           if (IsDlgButtonChecked(hdlg, IDC_INTENS_EN) != 0)
  1630.             Camera.EnableIntensity();
  1631.           else
  1632.             Camera.DisableIntensity();
  1633.  
  1634.           if (IsDlgButtonChecked(hdlg, IDC_CONTRAST_EN) != 0)
  1635.             Camera.EnableContrast();
  1636.           else
  1637.             Camera.DisableContrast();
  1638.  
  1639.           if (IsDlgButtonChecked(hdlg, IDC_GAMMA_EN) != 0)
  1640.             Camera.EnableGamma();
  1641.           else
  1642.             Camera.DisableGamma();
  1643.  
  1644.           if (IsDlgButtonChecked(hdlg, IDC_JITTER_EN) != 0)
  1645.             Camera.EnableJitter();
  1646.           else
  1647.             Camera.DisableJitter();
  1648.  
  1649.           if (DispType == H_BMAP)
  1650.           {
  1651.             // Instruct parent window to update client area
  1652.             SendMessage(GetParent(hdlg), WM_COMMAND,
  1653.                 IDD_UPD_DISPLAY, 0L);
  1654.           }
  1655.  
  1656.           if (GET_WM_COMMAND_ID(wparam, lparam) == IDOK)
  1657.           {
  1658.             DestroyWindow(hdlg);        // Close dialog box
  1659.             hSetDisplayDlg = NULL;
  1660.           }
  1661.  
  1662.           return TRUE;
  1663.         case IDCANCEL:
  1664.           DestroyWindow(hdlg);          // Close dialog box
  1665.           hSetDisplayDlg = NULL;
  1666.           return TRUE;
  1667.         default:
  1668.           break;
  1669.       }
  1670.       break;
  1671.     case WM_CLOSE:
  1672.       DestroyWindow(hdlg);      // Close dialog box
  1673.       hSetDisplayDlg = NULL;
  1674.       return TRUE;
  1675.     default:
  1676.       break;
  1677.   }
  1678.   return FALSE;
  1679. }
  1680.  
  1681. // Set color parameters
  1682. BOOL CALLBACK SetColor( HWND hdlg, UINT msg, WPARAM
  1683.     wparam, LPARAM lparam )
  1684. {
  1685.   static int c_type;    // Color type
  1686.   static BOOL r_flag;   // Color resolution flag
  1687.  
  1688.   switch (msg)
  1689.   {
  1690.     case WM_INITDIALOG:
  1691.       c_type = Camera.GetColorType();
  1692.       r_flag = Bitmap.GetRGBFlag();
  1693.  
  1694.       CheckRadioButton(hdlg, IDC_RGB, IDC_PSEUDO, c_type +
  1695.           IDC_RGB);
  1696.  
  1697.       if (Bitmap.GetPaletteFlag() == FALSE)
  1698.       {
  1699.         if (r_flag == TRUE)
  1700.           CheckRadioButton(hdlg, IDC_COLRES_24, IDC_COLRES_8,
  1701.               IDC_COLRES_24);
  1702.         else
  1703.           CheckRadioButton(hdlg, IDC_COLRES_24, IDC_COLRES_8,
  1704.               IDC_COLRES_8);
  1705.       }
  1706.       else
  1707.       {
  1708.         // Disable 24-bit color resolution button
  1709.         EnableWindow(GetDlgItem(hdlg, IDC_COLRES_24),
  1710.             FALSE);
  1711.  
  1712.         CheckRadioButton(hdlg, IDC_COLRES_24, IDC_COLRES_8,
  1713.             IDC_COLRES_8);
  1714.       }
  1715.  
  1716.       CenterDialog(hdlg);
  1717.       return TRUE;
  1718.     case WM_COMMAND:
  1719.       switch (GET_WM_COMMAND_ID(wparam, lparam))
  1720.       {
  1721.         case IDC_RGB:
  1722.         case IDC_MONO:
  1723.         case IDC_PSEUDO:
  1724.           switch (wparam - IDC_RGB)
  1725.           {
  1726.             case 0:
  1727.               c_type = SC_RGB;
  1728.               break;
  1729.             case 1:
  1730.               c_type = SC_MONO;
  1731.               break;
  1732.             case 2:
  1733.               c_type = SC_PSEUDO;
  1734.               break;
  1735.             default:
  1736.               break;
  1737.           }
  1738.  
  1739.           CheckRadioButton(hdlg, IDC_RGB, IDC_PSEUDO,
  1740.               wparam);
  1741.           break;
  1742.         case IDC_COLRES_8:
  1743.         case IDC_COLRES_24:
  1744.           r_flag = (wparam - IDC_COLRES_24 == 0) ? TRUE :
  1745.               FALSE;
  1746.  
  1747.           CheckRadioButton(hdlg, IDC_COLRES_24,
  1748.               IDC_COLRES_8, wparam);
  1749.           break;
  1750.         case IDC_HELP_SETDISPLAY:       // Display Help
  1751.           WinHelp(hdlg, HelpFileName, HELP_CONTEXT,
  1752.               (DWORD) HELP_SETCOLOR);
  1753.           break;
  1754.         case IDOK:
  1755.         case IDC_UPDATE:
  1756.           // Set display color type
  1757.           Camera.SetColorType(c_type);
  1758.  
  1759.           // Set display color resolution
  1760.           Bitmap.SetRGBFlag(r_flag);
  1761.  
  1762.           if (DispType == H_BMAP)
  1763.           {
  1764.             // Instruct parent window to update client area
  1765.             SendMessage(GetParent(hdlg), WM_COMMAND,
  1766.                 IDD_UPD_DISPLAY, 0L);
  1767.           }
  1768.  
  1769.           if (GET_WM_COMMAND_ID(wparam, lparam) == IDOK)
  1770.           {
  1771.             DestroyWindow(hdlg);        // Close dialog box
  1772.             hSetColorDlg = NULL;
  1773.           }
  1774.  
  1775.           return TRUE;
  1776.         case IDCANCEL:
  1777.           DestroyWindow(hdlg);          // Close dialog box
  1778.           hSetColorDlg = NULL;
  1779.           return TRUE;
  1780.         default:
  1781.           break;
  1782.       }
  1783.       break;
  1784.     case WM_CLOSE:
  1785.       DestroyWindow(hdlg);      // Close dialog box
  1786.       hSetColorDlg = NULL;
  1787.       return TRUE;
  1788.     default:
  1789.       break;
  1790.   }
  1791.   return FALSE;
  1792. }
  1793.  
  1794. // Abort calculations dialog box
  1795. BOOL CALLBACK AbortCalc( HWND hdlg, UINT msg, WPARAM
  1796.     wparam, LPARAM lparam )
  1797. {
  1798.   switch (msg)
  1799.   {
  1800.     case WM_INITDIALOG:
  1801.       SetFocus(GetDlgItem(hdlg, IDCANCEL));
  1802.       CenterDialog(hdlg);
  1803.       return TRUE;
  1804.     case WM_COMMAND:
  1805.       AbortFlag = TRUE;
  1806.       return TRUE;
  1807.     default:
  1808.       break;
  1809.   }
  1810.   return FALSE;
  1811. }
  1812.  
  1813. // Rendering calculations dialog box
  1814. BOOL CALLBACK RenderMsg( HWND hdlg, UINT msg, WPARAM
  1815.     wparam, LPARAM lparam )
  1816. {
  1817.   switch (msg)
  1818.   {
  1819.     case WM_INITDIALOG:
  1820.       CenterDialog(hdlg);
  1821.       return TRUE;
  1822.     default:
  1823.       break;
  1824.   }
  1825.   return FALSE;
  1826. }
  1827.  
  1828. // Display About dialog box
  1829. BOOL CALLBACK About( HWND hdlg, UINT msg, WPARAM wparam,
  1830.     LPARAM lparam )
  1831. {
  1832.   switch (msg)
  1833.   {
  1834.     case WM_INITDIALOG:
  1835.       CenterDialog(hdlg);
  1836.       return TRUE;
  1837.     case WM_COMMAND:
  1838.       switch (GET_WM_COMMAND_ID(wparam, lparam))
  1839.       {
  1840.         case IDOK:
  1841.         case IDCANCEL:
  1842.           EndDialog(hdlg, TRUE);
  1843.           return TRUE;
  1844.         default:
  1845.           break;
  1846.       }
  1847.       break;
  1848.     default:
  1849.       break;
  1850.   }
  1851.   return FALSE;
  1852. }
  1853.  
  1854. // Set camera movement type
  1855. static void SetMovementType( HMENU hmenu, UINT menu_id )
  1856. {
  1857.   HMENU hintm;  // Interactive menu handle
  1858.   BOOL check;   // Check mark status
  1859.  
  1860.   // Get interactive menu handle
  1861.   hintm = GetSubMenu(GetSubMenu(hmenu, MENU_CAMERA_POS),
  1862.       MENU_INTERACTIVE_POS);
  1863.  
  1864.   // Save current menu item state
  1865.   check = GetMenuState(hintm, menu_id, MF_BYCOMMAND) &
  1866.       MF_CHECKED;
  1867.  
  1868.   // Clear menu item check marks
  1869.   CheckMenuItem(hintm, IDM_SETDOLLY, MF_UNCHECKED);
  1870.   CheckMenuItem(hintm, IDM_SETORBIT, MF_UNCHECKED);
  1871.   CheckMenuItem(hintm, IDM_SETPAN, MF_UNCHECKED);
  1872.   CheckMenuItem(hintm, IDM_SETROTATE, MF_UNCHECKED);
  1873.   CheckMenuItem(hintm, IDM_SETTILT, MF_UNCHECKED);
  1874.   CheckMenuItem(hintm, IDM_SETZOOM, MF_UNCHECKED);
  1875.  
  1876.   if (check == FALSE)
  1877.   {
  1878.     // Check current menu item
  1879.     CheckMenuItem(hintm, menu_id, MF_CHECKED);
  1880.  
  1881.     // Update camera movement type
  1882.     switch (menu_id)
  1883.     {
  1884.       case IDM_SETDOLLY:
  1885.         MoveType = H_DOLLY;
  1886.         break;
  1887.       case IDM_SETORBIT:
  1888.         MoveType = H_ORBIT;
  1889.         break;
  1890.       case IDM_SETPAN:
  1891.         MoveType = H_PAN;
  1892.         break;
  1893.       case IDM_SETROTATE:
  1894.         MoveType = H_ROTATE;
  1895.         break;
  1896.       case IDM_SETTILT:
  1897.         MoveType = H_TILT;
  1898.         break;
  1899.       case IDM_SETZOOM:
  1900.         MoveType = H_ZOOM;
  1901.         break;
  1902.       default:
  1903.         break;
  1904.     }
  1905.   }
  1906.   else
  1907.     MoveType = H_LOCK;  // Disable camera movement
  1908. }
  1909.  
  1910. // Disable all menu items
  1911. static void DisableMenu( HMENU hmenu )
  1912. {
  1913.   EnableMenuItem(hmenu, IDM_FILEOPEN, MF_GRAYED);
  1914.   EnableMenuItem(hmenu, IDM_SAVEAS, MF_GRAYED);
  1915.   EnableMenuItem(hmenu, IDM_DIRECTORY, MF_GRAYED);
  1916.   EnableMenuItem(hmenu, IDM_STATISTICS, MF_GRAYED);
  1917.   EnableMenuItem(hmenu, IDM_EXIT, MF_GRAYED);
  1918.   EnableMenuItem(hmenu, IDM_SETCAMERA, MF_GRAYED);
  1919.   EnableMenuItem(hmenu, IDM_SETVIEW, MF_GRAYED);
  1920.   EnableMenuItem(hmenu, IDM_DEFVIEW, MF_GRAYED);
  1921.   EnableMenuItem(GetSubMenu(hmenu, MENU_CAMERA_POS),
  1922.       MENU_INTERACTIVE_POS, MF_GRAYED | MF_BYPOSITION);
  1923.   EnableMenuItem(hmenu, IDM_WIREFRAME, MF_GRAYED);
  1924.   EnableMenuItem(hmenu, IDM_SHADED, MF_GRAYED);
  1925.   EnableMenuItem(hmenu, IDM_RENDER, MF_GRAYED);
  1926.   EnableMenuItem(hmenu, IDM_REDISPLAY, MF_GRAYED);
  1927.   EnableMenuItem(hmenu, IDM_SETDISPLAY, MF_GRAYED);
  1928.   EnableMenuItem(hmenu, IDM_SETCOLOR, MF_GRAYED);
  1929.   EnableMenuItem(hmenu, IDM_SETCONVERGE, MF_GRAYED);
  1930.   EnableMenuItem(hmenu, IDM_HELP_CONTENTS, MF_GRAYED);
  1931.   EnableMenuItem(hmenu, IDM_HELP_HELP, MF_GRAYED);
  1932.   EnableMenuItem(hmenu, IDM_HELP_BOOK, MF_GRAYED);
  1933.   EnableMenuItem(hmenu, IDM_ABOUT, MF_GRAYED);
  1934. }
  1935.  
  1936. // Enable menu items
  1937. static void EnableMenu( HMENU hmenu )
  1938. {
  1939.   EnableMenuItem(hmenu, IDM_FILEOPEN, MF_ENABLED);
  1940.   EnableMenuItem(hmenu, IDM_DIRECTORY, MF_ENABLED);
  1941.   EnableMenuItem(hmenu, IDM_STATISTICS, MF_ENABLED);
  1942.   EnableMenuItem(hmenu, IDM_EXIT, MF_ENABLED);
  1943.   EnableMenuItem(hmenu, IDM_SETCAMERA, MF_ENABLED);
  1944.   EnableMenuItem(hmenu, IDM_SETVIEW, MF_ENABLED);
  1945.   EnableMenuItem(hmenu, IDM_DEFVIEW, MF_ENABLED);
  1946.   EnableMenuItem(GetSubMenu(hmenu, MENU_CAMERA_POS),
  1947.       MENU_INTERACTIVE_POS, MF_ENABLED | MF_BYPOSITION);
  1948.   EnableMenuItem(hmenu, IDM_WIREFRAME, MF_ENABLED);
  1949.   EnableMenuItem(hmenu, IDM_SHADED, MF_ENABLED);
  1950.   EnableMenuItem(hmenu, IDM_REDISPLAY, MF_ENABLED);
  1951.   EnableMenuItem(hmenu, IDM_SETDISPLAY, MF_ENABLED);
  1952.   EnableMenuItem(hmenu, IDM_SETCOLOR, MF_ENABLED);
  1953.   EnableMenuItem(hmenu, IDM_SETCONVERGE, MF_ENABLED);
  1954.   EnableMenuItem(hmenu, IDM_HELP_CONTENTS, MF_ENABLED);
  1955.   EnableMenuItem(hmenu, IDM_HELP_HELP, MF_ENABLED);
  1956.   EnableMenuItem(hmenu, IDM_HELP_BOOK, MF_ENABLED);
  1957.   EnableMenuItem(hmenu, IDM_ABOUT, MF_ENABLED);
  1958.  
  1959.   if (RadCalcDone == FALSE)
  1960.     EnableMenuItem(hmenu, IDM_RENDER, MF_ENABLED);
  1961.  
  1962.   if (DispType == H_BMAP)
  1963.     EnableMenuItem(hmenu, IDM_SAVEAS, MF_ENABLED);
  1964. }
  1965.  
  1966. // Display bitmap
  1967. static BOOL DisplayBitmap( HWND hwnd, HWND hwnd_wire, HMENU
  1968.     hmenu )
  1969. {
  1970.   BOOL r_abort;     // Rendering abort flag
  1971.   BOOL repeat;      // Repeat flag
  1972.   BOOL status;      // Status flag
  1973.   DLGPROC pfunc;    // Exported fcn prolog ptr
  1974.  
  1975.   DisableMenu(hmenu);   // Disable menu items
  1976.  
  1977.   // Create modeless rendering calculations dialog box
  1978.   if (Camera.AntiAliasFlag() == TRUE)
  1979.   {
  1980.     InCalc = TRUE;
  1981.     pfunc = (DLGPROC) MakeProcInstance((FARPROC) AbortCalc,
  1982.         hInst);
  1983.     hAbortDlg = CreateDialog(hInst, "AbortRender", hwnd,
  1984.         (DLGPROC) pfunc);
  1985.     SetDlgItemInt(hAbortDlg, IDC_MAXPASS,
  1986.         Camera.GetMaxPass(), FALSE);
  1987.     SetDlgItemInt(hAbortDlg, IDC_NUMPASS,
  1988.         Camera.GetNumPass(), FALSE);
  1989.     SetDlgItemText(hAbortDlg, IDC_FILTERTYPE,
  1990.         Camera.GetCurrFilterName());
  1991.   }
  1992.   else
  1993.   {
  1994.     pfunc = (DLGPROC) MakeProcInstance((FARPROC) RenderMsg,
  1995.         hInst);
  1996.     hRenderDlg = CreateDialog(hInst, "RenderMsg", hwnd,
  1997.         (DLGPROC) pfunc);
  1998.   }
  1999.  
  2000.   // Record shaded display
  2001.   r_abort = FALSE;
  2002.   do
  2003.   {
  2004.     if ((status = Camera.Shoot(&Environment, &Bitmap,
  2005.         &repeat)) == FALSE)
  2006.       break;
  2007.  
  2008.     if (Camera.AntiAliasFlag() == TRUE)
  2009.     {
  2010.       // Update dialog box
  2011.       SetDlgItemInt(hAbortDlg, IDC_NUMPASS,
  2012.           Camera.GetNumPass(), FALSE);
  2013.  
  2014.       // Check for user-requested abort
  2015.       if (CheckAbort() == TRUE)
  2016.       {
  2017.         r_abort = TRUE;
  2018.         AbortFlag = FALSE;
  2019.         Camera.Abort();
  2020.         break;
  2021.       }
  2022.     }
  2023.   }
  2024.   while (repeat == TRUE);
  2025.  
  2026.   // Close rendering calculations dialog box
  2027.   if (Camera.AntiAliasFlag() == TRUE)
  2028.   {
  2029.     InCalc = FALSE;
  2030.     DestroyWindow(hAbortDlg);
  2031.   }
  2032.   else
  2033.     DestroyWindow(hRenderDlg);
  2034.  
  2035.   FreeProcInstance((FARPROC) pfunc);
  2036.   UpdateWindow(hwnd);
  2037.  
  2038.   if (status == TRUE && r_abort == FALSE)
  2039.   {
  2040.     // 256-color display required ?
  2041.     if (Bitmap.GetRGBFlag() == FALSE)
  2042.     {
  2043.       // Create modeless color quantization dialog box
  2044.       pfunc = (DLGPROC) MakeProcInstance((FARPROC)
  2045.           RenderMsg, hInst);
  2046.       hRenderDlg = CreateDialog(hInst, "QuantizeMsg", hwnd,
  2047.           (DLGPROC) pfunc);
  2048.  
  2049.       // Perform color quantization
  2050.       status = Bitmap.QuantizeColors();
  2051.  
  2052.       // Close color quantization dialog box
  2053.       DestroyWindow(hRenderDlg);
  2054.       FreeProcInstance((FARPROC) pfunc);
  2055.       UpdateWindow(hwnd);
  2056.     }
  2057.   }
  2058.  
  2059.   if (status == TRUE)   // Check for error
  2060.   {
  2061.     if (DispType == H_WIRE)
  2062.     {
  2063.       // Erase wireframe metafile
  2064.       Wire.Erase();
  2065.  
  2066.       // Destroy wireframe window
  2067.       DestroyWindow(hwnd_wire);
  2068.     }
  2069.  
  2070.     if (r_abort == FALSE)
  2071.     {
  2072.       DispType = H_BMAP;
  2073.  
  2074.       // Initialize scroll bar manager
  2075.       pScroll->Init(Camera.GetWidth(), Camera.GetHeight());
  2076.  
  2077.       // Enable Save As menu item
  2078.       EnableMenuItem(hmenu, IDM_SAVEAS, MF_ENABLED);
  2079.     }
  2080.     else
  2081.     {
  2082.       DispType = H_NONE;
  2083.       pScroll->Hide();      // Hide scroll bars
  2084.     }
  2085.   }
  2086.   else
  2087.     OutOfMemory();      // Report error
  2088.  
  2089.   // Redraw display (via WM_PAINT)
  2090.   InvalidateRect(hwnd, NULL, TRUE);
  2091.  
  2092.   EnableMenu(hmenu);    // Enable menu items
  2093.  
  2094.   if (status == TRUE && r_abort == FALSE)
  2095.     return TRUE;
  2096.   else
  2097.     return FALSE;
  2098. }
  2099.  
  2100. // Update camera dolly
  2101. static void UpdateDolly( int mdy )
  2102. {
  2103.   double dist_mult;     // Dolly distance multiplier
  2104.  
  2105.   // Calculate dolly distance (range -1.0 to 1.0)
  2106.   dist_mult = (double) mdy / (double)
  2107.       GetSystemMetrics(SM_CYSCREEN);
  2108.  
  2109.   Camera.Dolly(dist_mult);  // Dolly camera
  2110.  
  2111.   // Update modeless View Parameters dialog box
  2112.   UpdateViewDialog();
  2113. }
  2114.  
  2115. // Update camera orbit
  2116. static void UpdateOrbit( int mdx, int mdy )
  2117. {
  2118.   double h_rotate;  // Horizontal rotation angle
  2119.   double v_rotate;  // Vertical rotation angle
  2120.  
  2121.   // Calculate horizontal rotation angle (range:
  2122.   // -aspect_ratio to aspect_ratio)
  2123.   h_rotate = PI * (double) mdx / (4.0 * (double)
  2124.       GetSystemMetrics(SM_CYSCREEN));
  2125.  
  2126.   // Calculate vertical rotation angle (range: -1 to 1)
  2127.   v_rotate = PI * (double) mdy / (4.0 * (double)
  2128.       GetSystemMetrics(SM_CYSCREEN));
  2129.  
  2130.   // Orbit camera
  2131.   Camera.Orbit(h_rotate, v_rotate);
  2132.  
  2133.   // Update modeless View Parameters dialog box
  2134.   UpdateViewDialog();
  2135. }
  2136.  
  2137. // Update camera pan
  2138. static void UpdatePan( int mdx, int mdy )
  2139. {
  2140.   double horz_mult;     // Horizontal pan multiplier
  2141.   double vert_mult;     // Vertical pan multiplier
  2142.  
  2143.   // Calculate horizontal pan multiplier (range -1.0 *
  2144.   // aspect_ratio to 1.0 * aspect_ratio)
  2145.   horz_mult = (double) mdx / (double)
  2146.       GetSystemMetrics(SM_CYSCREEN);
  2147.  
  2148.   // Calculate vertical pan multiplier (range -1.0 to
  2149.   // 1.0)
  2150.   vert_mult = (double) mdy / (double)
  2151.       GetSystemMetrics(SM_CYSCREEN);
  2152.  
  2153.   Camera.Pan(horz_mult, vert_mult);     // Pan camera
  2154.  
  2155.   // Update modeless View Parameters dialog box
  2156.   UpdateViewDialog();
  2157. }
  2158.  
  2159. // Update camera rotate
  2160. static void UpdateRotate( int mdx, int mdy )
  2161. {
  2162.   double h_rotate;  // Horizontal rotation angle
  2163.   double v_rotate;  // Vertical rotation angle
  2164.  
  2165.   // Calculate horizontal rotation angle (range:
  2166.   // -aspect_ratio to aspect_ratio)
  2167.   h_rotate = PI * (double) mdx / (4.0 * (double)
  2168.       GetSystemMetrics(SM_CYSCREEN));
  2169.  
  2170.   // Calculate vertical rotation angle (range: -1 to 1)
  2171.   v_rotate = PI * (double) mdy / (4.0 * (double)
  2172.       GetSystemMetrics(SM_CYSCREEN));
  2173.  
  2174.   // Rotate camera
  2175.   Camera.Rotate(h_rotate, v_rotate);
  2176.  
  2177.   // Update modeless View Parameters dialog box
  2178.   UpdateViewDialog();
  2179. }
  2180.  
  2181. // Update camera tilt
  2182. static void UpdateTilt( int mdx )
  2183. {
  2184.   double tilt_angle;    // Tilt angle
  2185.  
  2186.   // Calculate rotation angle (range: -1 to 1)
  2187.   tilt_angle = PI * (double) mdx / (4.0 * (double)
  2188.       GetSystemMetrics(SM_CXSCREEN));
  2189.  
  2190.   // Tilt camera
  2191.   Camera.Tilt(tilt_angle);
  2192.  
  2193.   // Update modeless Camera Parameters dialog box
  2194.   UpdateCameraDialog();
  2195. }
  2196.  
  2197. // Update camera zoom
  2198. static void UpdateZoom( int mdy )
  2199. {
  2200.   double vd_mult;   // View distance multiplier
  2201.  
  2202.   // Calculate view distance multiplier (range 0.25 to 4.0)
  2203.   vd_mult = pow(2.0, (2.0 + (double) (2 * mdy) / (double)
  2204.       GetSystemMetrics(SM_CYSCREEN))) / 4.0;
  2205.  
  2206.   Camera.Zoom(vd_mult);     // Zoom camera
  2207.  
  2208.   // Update modeless Camera Parameters dialog box
  2209.   UpdateCameraDialog();
  2210. }
  2211.  
  2212. // Update modeless Camera Parameters dialog box
  2213. static void UpdateCameraDialog()
  2214. {
  2215.   if (hSetCameraDlg != NULL)
  2216.   {
  2217.     // Update view distance edit control
  2218.     SetDlgItemFloat(hSetCameraDlg, IDC_VDIST,
  2219.         Camera.GetViewDist());
  2220.  
  2221.     // Update front distance edit control
  2222.     SetDlgItemFloat(hSetCameraDlg, IDC_FDIST,
  2223.         Camera.GetFrontDist());
  2224.  
  2225.     // Update back distance edit control
  2226.     SetDlgItemFloat(hSetCameraDlg, IDC_BDIST,
  2227.         Camera.GetBackDist());
  2228.  
  2229.     // Update camera tilt angle
  2230.     SetDlgItemFloat(hSetCameraDlg, IDC_CAMTILT,
  2231.         RadToDeg(Camera.GetTiltAngle()));
  2232.   }
  2233. }
  2234.  
  2235. // Update modeless View Parameters dialog box
  2236. static void UpdateViewDialog()
  2237. {
  2238.   if (hSetViewDlg != NULL)
  2239.   {
  2240.     // Update eye position edit controls
  2241.     SetDlgItemFloat(hSetViewDlg, IDC_EYE_X,
  2242.         Camera.GetEyePosn().GetX());
  2243.     SetDlgItemFloat(hSetViewDlg, IDC_EYE_Y,
  2244.         Camera.GetEyePosn().GetY());
  2245.     SetDlgItemFloat(hSetViewDlg, IDC_EYE_Z,
  2246.         Camera.GetEyePosn().GetZ());
  2247.  
  2248.     // Update focus position edit controls
  2249.     SetDlgItemFloat(hSetViewDlg, IDC_FOCUS_X,
  2250.         Camera.GetFocusPosn().GetX());
  2251.     SetDlgItemFloat(hSetViewDlg, IDC_FOCUS_Y,
  2252.         Camera.GetFocusPosn().GetY());
  2253.     SetDlgItemFloat(hSetViewDlg, IDC_FOCUS_Z,
  2254.         Camera.GetFocusPosn().GetZ());
  2255.   }
  2256. }
  2257.  
  2258. // Display Interactive popup menu
  2259. static void DispInteractMenu( HWND hwnd, HMENU hmenu, POINT
  2260.     point )
  2261. {
  2262.   ClientToScreen(hwnd, (LPPOINT) &point);
  2263.   TrackPopupMenu(hmenu, 0, point.x, point.y, 0, hwnd, NULL);
  2264. }
  2265.  
  2266. // Get floating point dialog item
  2267. static double GetDlgItemFloat( HWND hdlg, int id )
  2268. {
  2269.   (void) GetDlgItemText(hdlg, id, StrBuffer,
  2270.       sizeof(StrBuffer));
  2271.   return atof(StrBuffer);
  2272. }
  2273.  
  2274. // Set floating point dialog item
  2275. static void SetDlgItemFloat( HWND hdlg, int id, double num )
  2276. {
  2277.   sprintf(StrBuffer, "%6.5f", num);
  2278.   SetDlgItemText(hdlg, id, StrBuffer);
  2279. }
  2280.  
  2281. // Calculate wireframe window dimensions
  2282. static void CalcWireDim( short client_x, short client_y,
  2283.     short *pxchild, short *pychild )
  2284. {
  2285.   double client_aspect;
  2286.   double child_aspect;
  2287.  
  2288.   if (client_y > 0)
  2289.   {
  2290.     client_aspect = (double) client_x / (double) client_y;
  2291.     child_aspect = (double) Camera.GetWidth() / (double)
  2292.         Camera.GetHeight();
  2293.     if (client_aspect >= child_aspect)
  2294.     {
  2295.       *pychild = (short) max(client_y - Offset * 2, Offset);
  2296.       *pxchild = (short) ((double) *pychild * child_aspect);
  2297.     }
  2298.     else
  2299.     {
  2300.       *pxchild = (short) max(client_x - Offset * 2, Offset);
  2301.       *pychild = (short) ((double) *pxchild / child_aspect);
  2302.     }
  2303.   }
  2304.   else
  2305.     *pxchild = *pychild = Offset;
  2306. }
  2307.  
  2308. // Process WM_KEYDOWN message
  2309. static void DoKeyDown( HWND hwnd, WPARAM wparam )
  2310. {
  2311.   switch (GET_WM_COMMAND_ID(wparam, lparam))
  2312.   {
  2313.     case VK_HOME:
  2314.       SendMessage(hwnd, WM_VSCROLL, SB_TOP, 0L);
  2315.       break;
  2316.     case VK_END:
  2317.       SendMessage(hwnd, WM_VSCROLL, SB_BOTTOM, 0L);
  2318.       break;
  2319.     case VK_PRIOR:
  2320.       SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, 0L);
  2321.       break;
  2322.     case VK_NEXT:
  2323.       SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, 0L);
  2324.       break;
  2325.     case VK_UP:
  2326.       SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0L);
  2327.       break;
  2328.     case VK_DOWN:
  2329.       SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0L);
  2330.       break;
  2331.     case VK_LEFT:
  2332.       SendMessage(hwnd, WM_HSCROLL, SB_PAGEUP, 0L);
  2333.       break;
  2334.     case VK_RIGHT:
  2335.       SendMessage(hwnd, WM_HSCROLL, SB_PAGEDOWN, 0L);
  2336.       break;
  2337.   }
  2338. }
  2339.  
  2340. // Check for user-requested abort
  2341. static BOOL CheckAbort()
  2342. {
  2343.   MSG msg;      // Window message
  2344.  
  2345.   // Process application message queue
  2346.   while ((AbortFlag == FALSE) && (PeekMessage(&msg, NULL,
  2347.       0, 0, PM_REMOVE)))
  2348.   {
  2349.     if (IsDialogMessage(hAbortDlg, &msg) == FALSE)
  2350.     {
  2351.       TranslateMessage(&msg);
  2352.       DispatchMessage(&msg);
  2353.     }
  2354.   }
  2355.  
  2356.   return AbortFlag;
  2357. }
  2358.  
  2359. // Center dialog box
  2360. static void CenterDialog( HWND hdlg )
  2361. {
  2362.   int height;   // Dialog box height
  2363.   int width;    // Dialog box width
  2364.   RECT drc;     // Dialog box coordinates
  2365.   RECT wrc;     // Parent window coordinates
  2366.  
  2367.   // Get dialog box coordinates
  2368.   GetWindowRect(hdlg, &drc);
  2369.   height = drc.bottom - drc.top;
  2370.   width = drc.right - drc.left;
  2371.  
  2372.   // Get parent window coordinates
  2373.   GetWindowRect(GetWindow(hdlg, GW_OWNER), &wrc);
  2374.  
  2375.   // Center dialog box in parent window
  2376.   MoveWindow(hdlg, max(0, (wrc.left + wrc.right - width) /
  2377.       2), max(0, (wrc.top + wrc.bottom - height) / 2),
  2378.      width, height, FALSE);
  2379. }
  2380.